<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>光线投射</title>
        <style>
            body {
                margin: 0;
                /* 隐藏body窗口区域滚动条 */
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <script type="module">
            import * as THREE from 'https://cdn.skypack.dev/three@v0.130.1'
            import { OrbitControls } from 'https://cdn.skypack.dev/three@v0.130.1/examples/jsm/controls/OrbitControls.js'
            import { GLTFLoader } from 'https://cdn.skypack.dev/three@v0.130.1/examples/jsm/loaders/GLTFLoader.js'
            import Stats from 'https://cdn.skypack.dev/three@v0.130.1/examples/jsm/libs/stats.module.js'
            import {GUI} from 'https://cdn.skypack.dev/three@v0.130.1/examples/jsm/libs/dat.gui.module.js'
            
            let controls = null, INTERSECTED = null
            const raycaster = new THREE.Raycaster();
            const mouse = new THREE.Vector2();

            let Game = {
                tickLength: 16, 				// 20Hz
                lastTick: performance.now(),	// 最后更新时间
                stopKey: 0,
                width: window.innerWidth,
                height: window.innerHeight,
                renderer: null,
                camera: null,
                scene: null,
                clock: new THREE.Clock(),
                stats: new Stats(),
                init: function(){
                    this.scene = new THREE.Scene()
                    
                    /** 相机设置  */
                    let k = this.width / this.height; //窗口宽高比
                    let s = 200; //三维场景显示范围控制系数，系数越大，显示的范围越大
                    this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
                    // this.camera = new THREE.PerspectiveCamera(60, this.width / this.height, 1, 1000)
                    this.camera.position.set( 0, 0, 100 )
                    this.camera.lookAt( 0, 0, 0 )
                   
                    this.lighting()

                    /** 创建场景对象Scene */
                    this.add()
                    
                    /** 创建渲染器对象 */
                    this.renderer = new THREE.WebGLRenderer({
                        antialias: true
                    })
                    this.renderer.setPixelRatio( window.devicePixelRatio )
                    this.renderer.setSize(this.width, this.height)
                    this.renderer.setClearColor(0xb9d3ff, 1)
                    this.renderer.setAnimationLoop(render)
                    document.body.appendChild(this.renderer.domElement)
                    document.body.appendChild(this.stats.dom)
                   
                    // 创建控件对象
                    controls = new OrbitControls(this.camera, this.renderer.domElement)
                    
                    const gui = new GUI();
                    for (let key in params) {
                        if (key.endsWith("_desc")) continue
                        gui.add(params, key ).name(params[key + "_desc"]);
                    }

                    window.onresize = function () {
                        Game.width = window.innerWidth; //窗口宽度
                        Game.height = window.innerHeight; //窗口高度
                        if (Game.renderer == null) return
                        Game.renderer.setSize(Game.width, Game.height);//设置渲染区域尺寸
                        if (Game.camera == null) return
                        k = Game.width / Game.height; //窗口宽高比
                        //修改相机对象属性
                        Game.camera.left = -s * k
                        Game.camera.right = s * k
                        Game.camera.top = s
                        Game.camera.bottom = -s
                        Game.camera.aspect = k
                        Game.camera.updateProjectionMatrix()
                    }
                    document.onkeydown = function (e) {
                        e = e || window.event;  //标准化事件对象
                        let t = e.target || e.srcElement;  //获取发生事件的元素，兼容IE和DOM
                        if (e.code == "Space") {  // 按下空格键 开始/暂停
                            // if (audio.isPlaying) {
                            //     audio.stop()
                            // } else {
                            //     audio.play()
                            // }
                            // console.log("audio: " + audio.isPlaying)
                        }
                        console.log(e.code)
                    }
                    document.onmousemove = function onMouseMove( event ) {
                        // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
                        mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
                        mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
                    }
                }, 
                lighting: function(){
                    if (this.scene == null ) return
                    /** 光源设置  */
                    // 点光源
                    let point = new THREE.PointLight(0xffffff)
                    point.position.set(400, 200, 300); //点光源位置

                    point.castShadow = true;

                    point.shadow.mapSize.width = 1024;
                    point.shadow.mapSize.height = 1024;

                    const d = 300;

                    point.shadow.camera.left = - d;
                    point.shadow.camera.right = d;
                    point.shadow.camera.top = d;
                    point.shadow.camera.bottom = - d;

                    point.shadow.camera.far = 1000;

                    //点光源添加到场景中
                    this.scene.add(point)
                    //环境光
                    this.scene.add(new THREE.AmbientLight(0x888888))
                },
                update: function(tFrame) {
                    if (tFrame === undefined) {
                        tFrame = performance.now()
                        Game.lastTick = performance.now()
                    }
                    let nextTick = Game.lastTick + Game.tickLength
                    let tickNum = 0
                    if (tFrame > nextTick) {
                        tickNum = Math.floor((tFrame - Game.lastTick) / Game.tickLength)
                    }
                    Game.lastTick = tFrame
                    this.stats.update()

                    // 通过摄像机和鼠标位置更新射线
                    raycaster.setFromCamera( mouse, this.camera );

                    // 计算物体和射线的焦点
                    const intersects = raycaster.intersectObjects( this.scene.children );
                    // console.log(intersects)
                    if (intersects.length > 0) {
                        if (INTERSECTED !== intersects[0]) {
                            if (INTERSECTED) INTERSECTED.object.material.color.set(INTERSECTED.currentColor)
                            INTERSECTED = intersects[0]
                            INTERSECTED.currentColor = INTERSECTED.object.material.color.clone()
                            INTERSECTED.object.material.color.set(0xff0000)
                            console.log(INTERSECTED.currentColor)
                        }
                        
                    } else {
                        if (INTERSECTED) INTERSECTED.object.material.color.set(INTERSECTED.currentColor)
                        INTERSECTED = null
                    }
                    //执行渲染操作   指定场景、相机作为参数
                    Game.renderer.render(Game.scene, Game.camera);
                },
                add: function() {
                    let axisHelper = new THREE.AxesHelper(250)
                    this.scene.add(axisHelper)
                    function randomPos() {
                        return Math.floor(Math.floor((Math.random() - 0.5) * 300))
                    }
                    function randomRat() {
                        return Math.floor(Math.random() * 360) / Math.PI / 2
                    }
                    for (let i = 0; i < 300; ++i) {
                        let mesh = new THREE.Mesh(
                            new THREE.BoxGeometry(10, 10, 10), 
                            new THREE.MeshPhongMaterial({
                                color: 0xaaffdd,
                                side: THREE.DoubleSide, //两面可见
                                transparent: true,
                            }))
                        this.scene.add(mesh)
                        mesh.position.set(randomPos(), randomPos(), randomPos())
                        mesh.rotateX(randomRat())
                        mesh.rotateY(randomRat())
                        mesh.rotateZ(randomRat())
                    }
                    
                }
            }

            function render(tFrame) {
                Game.update()
                // Game.stopKey = requestAnimationFrame(render)
            }
            const params = {
                // enableWind: true,
                // enableWind_desc: 'Enable wind',
                // showBall: false,
                // showBall_desc: 'Show ball',
                // togglePins: togglePins
            }
            Game.init()
            // render()
            // const controls = new OrbitControls(camera, renderer.domElement);//创建控件对象
        </script>
    </body>
</html>